package com.semidata.rtd.core.iplib;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class IpLib {
    private static List<IPEntry> ipEntries = new ArrayList<IPEntry>();
    
    public IpLib(String fileName) {
        init(fileName);
    }

    public void init(String fileName) {
        String line;
        IPEntry entry = null;
        InputStream is = null;
        BufferedReader reader = null;
        try {
            is = this.getClass().getClassLoader().getResourceAsStream(fileName);
            reader = new BufferedReader(new InputStreamReader(is));
            while ((line = reader.readLine()) != null) {
                entry = convertLine2Entry(line);
                if (entry != null) {
                    ipEntries.add(entry);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Collections.sort(ipEntries);
    }

    private IPEntry convertLine2Entry(String line) {
        IPEntry entry = null;
        if (line != null) {
            line = line.trim();
            String[] tmp = line.split(",");
            if (tmp.length >= 3) {
                long start = Long.valueOf(convertIP2Long(tmp[0]));
                long end = Long.valueOf(convertIP2Long(tmp[1]));
                String code = tmp[2].trim();
                entry = new IPEntry(start, end, code);
            }
        }
        return entry;
    }

    /**
     * 将ip地址转化成long类型
     * 
     * @param ip
     *            ip的String表示
     * @return 转换成功,返回ip的long类型表示;<br/>
     *         转化失败,返回-1
     */
    public Long convertIP2Long(String ip) {
        Long result = -1L;
        if (ip == null) {
            return -1L;
        }
        String[] ipSection = ip.split("\\.");
        try {
            if (ipSection.length == 4) {
                result = 0L;
                result += (Long.valueOf(ipSection[0]) << 24);
                result += (Long.valueOf(ipSection[1]) << 16);
                result += (Long.valueOf(ipSection[2]) << 8);
                result += (Long.valueOf(ipSection[3]));
            }
        } catch (Exception e) {
            e.printStackTrace();
            result = -1L;
        }
        return result;
    }

    public String getAreaCodeByIP(String ip) {
        IPEntry entry = binarySearch(ip);
        if (entry != null) {
            return entry.getCode();
        }
        return null;
    }

    public IPEntry binarySearch(String ip) {
        IPEntry entry = null;
        List<IPEntry> list = ipEntries;
        if (list != null) {
            long ipLong = convertIP2Long(ip);
            int left = 0, right = list.size() - 1, middle;
            while (left <= right) {
                middle = (left + right) / 2;
                entry = list.get(middle);
                if (entry.contains(ipLong)) {
                    return entry;
                }
                if (entry.before(ipLong)) {
                    left = middle + 1;
                } else {
                    right = middle - 1;
                }
            }
        }
        return null;
    }

    public Area getArea(String ip) {
        return new Area(binarySearch(ip).getCode());
    }
}
